home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / util / tracktls / part01 / src / tcopy.c < prev    next >
C/C++ Source or Header  |  1990-01-20  |  23KB  |  812 lines

  1. /*
  2.  * TRACKCOPY.C
  3.  *
  4.  * (C) Copyright Eddy Carroll 1989
  5.  *
  6.  * This program allows you to copy a portion of one disk device to a portion
  7.  * of another device which has similar sector and track layout, though may
  8.  * have a different number of cylinders. It is primarily intended to allow
  9.  * a recoverable ram disk like RAD: to be preloaded directly from floppy
  10.  * disk at high speed, a track at a time, instead of having to copy in files
  11.  * manually.
  12.  *
  13.  * Usage: tcopy <srcdevice> <destdevice> <start> <stop> <newstart>
  14.  *
  15.  * The parameters are as follows (example values are in brackets)
  16.  *
  17.  * <srcdevice>    The device to copy from (DF0:)
  18.  * <destdevice>    The device to copy to (RAD:)
  19.  * <start>        The starting cylinder on <srcdevice> (60)
  20.  * <end>        The ending cylinder on <srcdevice> (79)
  21.  * <newstart>    The starting cylinder on <destdevice> (0)
  22.  *
  23.  * For example, supposing you want to setup a disk that you can load into
  24.  * a 264K RAD (equals 24 cylinders of 2 tracks of 11 sectors of 512 bytes).
  25.  * First of all, you setup RAD: manually by mounting it and then copying
  26.  * in the appropriate files. Then you put a blank formatted disk into
  27.  * drive 0 and give the command:
  28.  *
  29.  *         tcopy RAD: DF0: 0 23 56
  30.  *
  31.  * Meaning: Copy cylinders 0-23 of RAD: to cylinders 56-79 of DF0:.
  32.  *
  33.  * You then add enough files to DF0: to make a minimal boot disk, taking care
  34.  * not to add more than (56-40 = 16) cylinders of data (or 176K), since
  35.  * this would cause the data you've just written directly onto the disk
  36.  * to be overwritten. Then put the command:
  37.  *
  38.  *        tcopy DF0: RAD: 56 79 0
  39.  *
  40.  * into your startup-sequence, and when you reboot, RAD: will be reloaded
  41.  * with the appropriate information.
  42.  * ----
  43.  * An additional option may be compiled in by defining the constant
  44.  * RAMBO at compile time. When this is done, tcopy will have
  45.  * some additional options which allow rad: to be automatically mounted
  46.  * and initialised. This is designed to remove the overhead of having
  47.  * to do a MOUNT RAD: in your startup-sequence. When this is the case,
  48.  * the following options may be specified before the rest of the command
  49.  * line. If none are specified, RAD: is not mounted. Defaults are in ().
  50.  *
  51.  *     -v<name>    Sets RAD: volume name to be <name>  ("RAMB0")
  52.  *     -n<name>    Sets RAD: device name to be <name>  ("RAD") (no colon!)
  53.  *     -d<name>    Sets RAD: exec device to be <name>  ("ramdrive.device")
  54.  *       -e<txt>       Echos <txt> to stdout
  55.  *       -a           Always do track copy, even if RAD: already mounted
  56.  *     -f#         Sets flags for OpenDevice() to #    (0)
  57.  *     -m#         Sets BufMemType to #                (1)
  58.  *     -p#         Sets boot priority to #             (-1)
  59.  *     -t#         Sets number of tracks(%) to #       (10)
  60.  *     -u#         Sets unit number of device to be #  (0)
  61.  *
  62.  * (%) Actually the number of cylinders, but people seem to like to think
  63.  *     of them as tracks.
  64.  */
  65.  
  66. #define TRUE            1
  67. #define FALSE            0
  68. #define LASTCHAR(s)        (s[strlen(s)-1])
  69.  
  70. #ifndef LATTICE_50
  71. #include "system.h"
  72. #endif
  73.  
  74. extern struct DosLibrary       *DOSBase;
  75.  
  76. typedef struct IORequest       IOREQ;
  77. typedef struct MsgPort         MSGPORT;
  78. typedef struct Process         PROC;
  79. typedef struct StandardPacket  STDPKT;
  80.  
  81. void inhibit(MSGPORT *devport, int mode);
  82. /*
  83.  *        Structure representing a disk device
  84.  */
  85. typedef struct {
  86.     char  *devname;            /* Name of exec device for this disk    */
  87.     int   isfloppy;            /* True if device is trackdisk.device    */
  88.     ULONG unit;                /* Unit number of above exec device        */
  89.     ULONG blocksize;        /* Number of bytes per block            */
  90.     ULONG blockspertrack;    /* Number of blocks/sectors per track    */
  91.     ULONG surfaces;            /* Number of tracks per cylinder        */
  92.     ULONG lowcyl;            /* Starting cylinder of disk on device     */
  93.     ULONG numcyl;            /* Number of cylinders on this disk        */
  94. } DISKDEV;
  95.  
  96. #ifdef RAMBO
  97. /************************** Declarations for RAMBO **************************/
  98.  
  99. struct ExpansionBase *ExpansionBase;
  100.  
  101. char execname[] = "ramdrive.device";
  102. char dosname[]  = "RAD";
  103. char *volname   = "RAMB0";
  104. int bootpri     = -1;
  105.  
  106. /*
  107.  *        Parameter block for mounting RAD:
  108.  */
  109. struct MountParamBlock {
  110.     char    *dosname;
  111.     char    *execname;
  112.     ULONG    unit;
  113.     ULONG    flags;
  114.     ULONG    size;
  115.     ULONG    blocksize;
  116.     ULONG    origin;
  117.     ULONG    surfaces;
  118.     ULONG    sectorperblock;
  119.     ULONG    sectorspertrack;
  120.     ULONG    reserved;
  121.     ULONG    prealloc;
  122.     ULONG    interleave;
  123.     ULONG    lowcyl;
  124.     ULONG    highcyl;
  125.     ULONG    numbuffers;
  126.     ULONG    bufmemtype;
  127. } mount = {
  128.     dosname,
  129.     execname,
  130.     0,                    /*  2: Unit number                        */
  131.     0,                    /*  3: OpenDevice() flags                */
  132.  
  133.     /* This is where the environment block starts */
  134.     11,                    /*  4: Table upper bound                */
  135.     512>>2,                /*  5: Number of longwords per block    */
  136.     0,                    /*  6: Sector origin - unused            */
  137.     2,                    /*  7: Number of surfaces                */
  138.     1,                    /*  8: Sectors per block - unused        */
  139.     11,                    /*  9: Sectors per track                */
  140.     2,                    /* 10: Reserved blocks - boot block        */
  141.     0,                    /* 11: Reserved blocks at end            */
  142.     0,                    /* 12: Interleave                        */
  143.     0,                    /* 13: Low cylinder                        */
  144.     10,                    /* 14: High cylinder                    */
  145.     5                     /* 15: Number of buffers                */
  146. };
  147.  
  148. /*********************** End of declarations for RAMBO *********************/
  149. #endif RAMBO
  150.  
  151. /*
  152.  *        Global variables
  153.  */
  154.  
  155. char *srcname;                    /* AmigaDos name of source device            */
  156. char *destname;                    /* AmigaDos name of destination device        */
  157. DISKDEV src[1];                    /* Source disk device                        */
  158. DISKDEV dest[1];                /* Destination disk device                    */
  159. struct IOStdReq *srcreq;        /* Standard request for source device        */
  160. struct IOStdReq *destreq;        /* Standard request for destination device    */
  161. MSGPORT *reqport;                /* Message port for replies from devices    */
  162. MSGPORT *destport;                /* Message port of process of dest. device    */
  163. void *buffer;                    /* Pointer to data buffer for track r/w        */
  164. long cylsize;                    /* Size in bytes of a single cylinder        */
  165. int    srcdevopen;                    /* True if source exec device is open        */
  166. int    destdevopen;                /* True if destination device is open        */
  167. int inhibited;                    /* True if destination device is inhibited    */
  168.  
  169.  
  170. /*
  171.  *        print()
  172.  *        -------
  173.  *        Outputs a message to stdout
  174.  */
  175. void print(char *s)
  176. {
  177.     Write(Output(), s, strlen(s));
  178. }
  179. #define print2(s1,s2)    (print(s1),print(s2))
  180. #define print3(s1,s2,s3) (print(s1),print(s2),print(s3))
  181.  
  182. /*
  183.  *        numtostr()
  184.  *        ----------
  185.  *        Simple little function which returns a pointer to a static string
  186.  *        representation of the passed in number.
  187.  */
  188. char *numtostr(int n)
  189. {
  190.     static char s[20];
  191.     int i = 19;
  192.  
  193.     s[19] = '\0';
  194.     if (n)
  195.         while (n) {
  196.             s[--i] = '0' + (n % 10);
  197.             n /= 10;
  198.         }
  199.     else
  200.         s[--i] = '0';
  201.     return(&s[i]);
  202. }
  203.  
  204.  
  205. /*
  206.  *        cleanup()
  207.  *        ---------
  208.  *        Closes all opened resources, and exits with specified error code.
  209.  */
  210. void cleanup(int code)
  211. {
  212.     if (buffer)
  213.         FreeMem(buffer, cylsize);
  214.  
  215.     if (srcdevopen) {
  216.         if (src->isfloppy) {    /* Turn off drive motor if floppy disk */
  217.             srcreq->io_Command = TD_MOTOR;
  218.             srcreq->io_Length = 0;
  219.             DoIO((IOREQ *)srcreq);
  220.         }
  221.         CloseDevice((IOREQ *)srcreq);
  222.     }
  223.     if (destdevopen) {
  224.         if (dest->isfloppy) {    /* Turn off drive motor if floppy disk */
  225.             destreq->io_Command = TD_MOTOR;
  226.             destreq->io_Length = 0;
  227.             DoIO((IOREQ *)destreq);
  228.         }
  229.         CloseDevice((IOREQ *)destreq);
  230.     }
  231.  
  232.     if (inhibited)
  233.         inhibit(destport, FALSE);
  234.  
  235.     if (srcreq)
  236.         DeleteStdIO(srcreq);
  237.     if (destreq)
  238.         DeleteStdIO(destreq);
  239.  
  240.     if (reqport)
  241.         DeletePort(reqport);
  242.  
  243. #ifdef RAMBO
  244.     if (ExpansionBase)
  245.         CloseLibrary((struct Library *)ExpansionBase);
  246. #endif RAMBO
  247.  
  248.     exit(code);
  249. }
  250.  
  251.  
  252. /*
  253.  *        chkabort()
  254.  *        ----------
  255.  *        A replacement for Lattice's chkabort(), which doesn't carry all
  256.  *        the extra baggage. If CTRL-C is detected, this function never
  257.  *        returns but instead calls cleanup. Since Lattice's exit() code
  258.  *        may call chkabort(), a check is made to ensure that cleanup()
  259.  *        only gets called once, otherwise there would be a problem if the
  260.  *        user pressed Ctrl-C twice in quick succession.
  261.  */
  262. void chkabort()
  263. {
  264.     static int gotctrlc = FALSE;
  265.     if (!gotctrlc && (SetSignal(0,0) & SIGBREAKF_CTRL_C)) {
  266.         gotctrlc = TRUE;
  267.         print("^C\n");
  268.         cleanup(20);
  269.     }
  270. }
  271.  
  272. /*
  273.  *        GetVolume()
  274.  *        -----------
  275.  *        This function searches the device list for the named volume, and
  276.  *        fills in the passed DISKDEV structure with information about the
  277.  *        volume. If the named volume is not a device, or is not a disk,
  278.  *        then FALSE is returned. It is not an error to pass in NULL as
  279.  *        a pointer to the DISKDEV structure. In this case, nothing will
  280.  *        be filled in, but TRUE or FALSE will be returned indicating whether
  281.  *        the device is a disk device or not.
  282.  */
  283. int GetVolume(char *devname, DISKDEV *dev)
  284. {
  285.     struct RootNode *rootnode;
  286.     struct DosInfo *dosinfo;
  287.     struct DeviceNode *devnode;
  288.     struct FileSysStartupMsg *startup;
  289.     struct DosEnvec *dosenvec;
  290.     unsigned char *p;
  291.     int namelen = strlen(devname);
  292.  
  293.     if (LASTCHAR(devname) != ':')    /* Device names must end with ':' */
  294.         return (FALSE);
  295.     /*
  296.      *        First of all, find the device
  297.      */
  298.     rootnode = (struct RootNode *)DOSBase->dl_Root;
  299.     dosinfo = (struct DosInfo *)BADDR(rootnode->rn_Info);
  300.     devnode = (struct DeviceNode *)BADDR(dosinfo->di_DevInfo);
  301.  
  302.     Forbid();    /* Make sure list doesn't change while we scan it */
  303.  
  304.     while (devnode != NULL) {
  305.         p = (unsigned char *)BADDR(devnode->dn_Name)+1;
  306.         if (!strnicmp(devname, p, namelen-1)) {    /* Don't compare the ':' */
  307.             /*
  308.              *        Matched name successfully. Now check if it's a device.
  309.              *        Note that we carry on searching if it's not a device
  310.              *        (rather than returning FALSE immediately) since there
  311.              *        may be a volume called RAD: as well as a device called
  312.              *        RAD:, for example.
  313.              */
  314.             if (devnode->dn_Type == DLT_DEVICE) {
  315.                 if (devnode->dn_Startup < 20)    /* Is there a startup bit?    */
  316.                     goto notfound;                /* If not, not disk device    */
  317.                     /* Eek! A GOTO! */
  318.  
  319.                 startup = (struct FileSysStartupMsg *)
  320.                                         BADDR(devnode->dn_Startup);
  321.  
  322.                 if (dev) {
  323.                     dev->devname = ((char *)BADDR(startup->fssm_Device))+1;
  324.                     dev->isfloppy = (!strcmp(TD_NAME, dev->devname));
  325.                     dev->unit = startup->fssm_Unit;
  326.                 }
  327.  
  328.                 if (startup->fssm_Environ < 20)
  329.                     goto notfound;
  330.                 /* Another GOTO! The Earth will end in 5 seconds... */
  331.  
  332.                 dosenvec = (struct DosEnvec *)BADDR(startup->fssm_Environ);
  333.  
  334.                 if (dev) {
  335.                     dev->blocksize        = dosenvec->de_SizeBlock << 2;
  336.                     dev->blockspertrack    = dosenvec->de_BlocksPerTrack;
  337.                     dev->surfaces        = dosenvec->de_Surfaces;
  338.                     dev->lowcyl            = dosenvec->de_LowCyl;
  339.                     dev->numcyl            = (dosenvec->de_HighCyl -
  340.                                                 dosenvec->de_LowCyl) + 1;
  341.                 }
  342.                 Permit();
  343.                 return (TRUE);
  344.             }
  345.         }
  346.         devnode = (struct DeviceNode *)BADDR(devnode->dn_Next);
  347.     }
  348. notfound:
  349.     Permit();
  350.     return (FALSE);
  351. }
  352.  
  353. /*
  354.  *        help()
  355.  *        ------
  356.  *        Prints out a help message about tcopy
  357.  */
  358. void help()
  359. {
  360.     print(
  361. "Tcopy (C) Copyright Eddy Carroll, January 1990. Freely distributable.\n"
  362. );
  363. #ifdef RAMBO
  364. #define print13(a,b,c,d,e,f,g,h,i,j,k,l,m) (print3(a,b,c),print3(d,e,f),\
  365.                                     print3(g,h,i),print3(j,k,l),print(m))
  366. print13(
  367. "Usage: tcopy <flags> <from> <to> <start> <end> <newstart>\n\n",
  368. "  <flags>     If any of the following are included, then RAD: will be\n",
  369. "              automatically mounted when tcopy is run:\n\n",
  370. "              -v<name>    Sets RAD: volume name to be <name> (\"RAMB0\")\n",
  371. "              -n<name>    Sets RAD: device name to be <name>   (\"RAD\")\n",
  372. "              -d<name>    Use exec device <name>   (\"ramdrive.device\")\n",
  373. "              \"-e<txt>\"   Prints <txt> to stdout\n",
  374. "              -a          Do trackcopy, even if RAD: already mounted\n",
  375. "              -f#         Sets flags for OpenDevice() to #         (0)\n",
  376. "              -m#         Sets BufMemType to #                     (1)\n",
  377. "              -p#         Sets boot priority to #                 (-1)\n",
  378. "              -t#         Sets number of tracks to #              (10)\n",
  379. "              -u#         Sets unit number of exec device to #     (0)\n\n"
  380. );
  381. #else
  382.     print("Usage: tcopy <from> <to> <start> <end> <newstart>\n\n");
  383. #endif RAMBO
  384.     print("  <from>      Device to copy from (e.g. DF0:)\n");
  385.     print("  <to>        Device to copy to (e.g. RAD:)\n");
  386.     print("  <start>     Cylinder to start reading from (e.g. 70)\n");
  387.     print("  <end>       Cylinder to end reading at (e.g. 79)\n");
  388.     print("  <newstart>  Cylinder to start writing at (e.g. 0)\n");
  389. }
  390.  
  391.  
  392. /*
  393.  *        opendevs()
  394.  *        ----------
  395.  *        Opens the source and destination devices, allocates buffer for
  396.  *        reading and writing etc. Note that if either device is a floppy
  397.  *        drive, the buffer must be allocated in chip memory or trackdisk.device
  398.  *        won't be able to blit into it.
  399.  */
  400. void opendevs()
  401. {
  402.     long memflags = 0;
  403.  
  404.     if (src->isfloppy || dest->isfloppy)
  405.         memflags |= MEMF_CHIP;
  406.  
  407.     cylsize = src->blocksize * src->blockspertrack * src->surfaces;
  408.     buffer = AllocMem(cylsize, memflags);
  409.     if (!buffer) {
  410.         print("Not enough memory for track buffer\n");
  411.         cleanup(20);
  412.     }
  413.  
  414.     reqport = (MSGPORT *)CreatePort(0,0);
  415.     if (!reqport) {
  416.         print("Couldn't allocate message port\n");
  417.         cleanup(20);
  418.     }
  419.  
  420.     srcreq    = CreateStdIO(reqport);
  421.     destreq = CreateStdIO(reqport);
  422.     if (!srcreq || !destreq) {
  423.         print("Couldn't allocate IO request - memory is low!\n");
  424.         cleanup(20);
  425.     }
  426.  
  427.     if (OpenDevice(src->devname, src->unit, (IOREQ *)srcreq, 0L)) {
  428.         print3("Can't open source ", src->devname, "\n");
  429.         cleanup(20);
  430.     }
  431.     srcdevopen = TRUE;
  432.  
  433.     if (OpenDevice(dest->devname, dest->unit, (IOREQ *)destreq, 0L)) {
  434.         print3("Can't open destination ", dest->devname, "\n");
  435.         cleanup(20);
  436.     }
  437.     destdevopen = TRUE;
  438. }
  439.  
  440. /*
  441.  *        copytracks()
  442.  *        ------------
  443.  *        This is where the actual work gets done. Tracks (cylinders actually)
  444.  *        are copied from start to end on the source device to newstart on
  445.  *        the destination device.
  446.  */
  447. void copytracks(int start, int end, int newstart)
  448. {
  449.     int cyl, retry, numcyls = (end - start) + 1;
  450.  
  451.     for (cyl = 0; cyl < numcyls; cyl++) {
  452.         /*
  453.          *        First read in track from source device
  454.          */
  455.         for (retry = 0; retry < 3; retry++) {
  456.             chkabort();
  457.             srcreq->io_Command = CMD_READ;
  458.             srcreq->io_Length  = cylsize;
  459.             srcreq->io_Offset  = (src->lowcyl + cyl + start) * cylsize;
  460.             srcreq->io_Data    = buffer;
  461.             if (!DoIO((IOREQ *)srcreq))
  462.                 break;        /* Succeeded, so break out of loop */
  463.         }
  464.         if (retry == 3) {
  465.             print3("Error reading track ", numtostr(cyl+start)," from disk\n");
  466.             cleanup(20);
  467.         }
  468.  
  469.         /*
  470.          *        Now write out track to destination device
  471.          */
  472.         for (retry = 0; retry < 3; retry++) {
  473.             chkabort();
  474.             destreq->io_Command = CMD_WRITE;
  475.             destreq->io_Length  = cylsize;
  476.             destreq->io_Offset  = (dest->lowcyl + cyl + newstart) * cylsize;
  477.             destreq->io_Data    = buffer;
  478.             if (!DoIO((IOREQ *)destreq))
  479.                 break;        /* Succeeded */
  480.         }
  481.         if (retry == 3) {
  482.             print3("Error writing track ", numtostr(cyl), " to disk\n");
  483.             cleanup(20);
  484.         }
  485.     }
  486. }
  487.  
  488.  
  489. /*
  490.  *        SendPacket()
  491.  *        ------------
  492.  *        ``Sort of'' simulates the ARP SendPacket() routine which sends
  493.  *        a packet to AmigaDos, and gets a reply if appropriate. What is
  494.  *        passed in is the action to be executed (one of the ACTION_xxx
  495.  *        definitions in dosextens.h), a pointer to a longword array of 7
  496.  *        arguments to be passed to the device, and the msgport of the device
  497.  *        as returned by DeviceProc("DF0:") for example. If result is non-NULL
  498.  *        then it should be a pointer to a two element array of ULONGs, and it
  499.  *        fills in the 0th element with the primary result, and the the
  500.  *        1st element with the secondary result.
  501.  */
  502. int SendPacket(ULONG action, void *args, MSGPORT *devport, ULONG *result)
  503. {
  504.     PROC *proc = (PROC *)FindTask(NULL);
  505.     STDPKT *packet;
  506.  
  507.     packet = (STDPKT *)AllocMem(sizeof(STDPKT), MEMF_CLEAR | MEMF_PUBLIC);
  508.     if (!packet)
  509.         return (FALSE);
  510.     packet->sp_Msg.mn_Node.ln_Name = (char *)&packet->sp_Pkt;
  511.     packet->sp_Pkt.dp_Link         = &packet->sp_Msg;
  512.     packet->sp_Pkt.dp_Port         = &proc->pr_MsgPort;
  513.     packet->sp_Pkt.dp_Type         = action;
  514.     memcpy(&packet->sp_Pkt.dp_Arg1, args, sizeof(ULONG) * 7);
  515.  
  516.     /*
  517.      *        Okay, we've done the necessary magic to create an AmigaDos
  518.      *        packet lookalike (thanks to Matt Dillon in Transactor V1.1).
  519.      *        Now we send the message to the Dos process, and get the reply.
  520.      *        Then our message will be filled in with the response from the
  521.      *        Dos process.
  522.      */
  523.     PutMsg(devport, (struct Message *)packet);
  524.     WaitPort(&proc->pr_MsgPort);
  525.     GetMsg(&proc->pr_MsgPort);
  526.     if (result) {
  527.         result[0] = packet->sp_Pkt.dp_Res1;
  528.         result[1] = packet->sp_Pkt.dp_Res2;
  529.     }
  530.     FreeMem(packet, sizeof(STDPKT));
  531.     return (TRUE);
  532. }
  533.  
  534.  
  535.  
  536. /*
  537.  *        inhibit()
  538.  *        ---------
  539.  *        This function inhibits (if mode is TRUE) or hibits (if mode is FALSE)
  540.  *        (is hibit the opposite of inhibit? Hmmm...) the specified device.
  541.  */
  542. void inhibit(MSGPORT *devport, int mode)
  543. {
  544.     ULONG pktargs[7];
  545.     int i;
  546.  
  547.     pktargs[0] = mode;            /* Select inhibit or opposite */
  548.     for (i = 1; i < 7; i++)        /* Clear other arguments      */
  549.         pktargs[i] = 0;
  550.  
  551.     if (!SendPacket(ACTION_INHIBIT, pktargs, devport, NULL)) {
  552.         print("Couldn't send inhibit packet to device\n");
  553.         cleanup(20);
  554.     }
  555. }
  556.  
  557.  
  558. #ifdef RAMBO
  559. /*
  560.  *        mountramdisk()
  561.  *        --------------
  562.  *        This procedure simply mounts the device specified in the mount
  563.  *        parameter block.
  564.  */
  565. int mountramdisk()
  566. {
  567.     struct DeviceNode *devnode;
  568.     long args[7];
  569.     int i;
  570.     char *diskname;
  571.     MSGPORT *devport;
  572.     static char dosname[200];    /* Temporary storage for dos device name */
  573.  
  574.     ExpansionBase = (struct ExpansionBase *)
  575.                         OpenLibrary("expansion.library", 0L);
  576.     if (!ExpansionBase) {
  577.         print("Couldn't open expansion.library\n");
  578.         cleanup(20);
  579.     }
  580.  
  581.     devnode = MakeDosNode(&mount);
  582.     if (!devnode)
  583.         return (FALSE);
  584.  
  585.     AddDosNode(bootpri, ADNF_STARTPROC, devnode);
  586.  
  587.     /*
  588.      *        Now we've mounted the device, let's try and rename it to
  589.      *        something different.
  590.      */
  591.     strcpy(dosname, mount.dosname);
  592.     strcat(dosname, ":");
  593.     devport = (MSGPORT *)DeviceProc(dosname);
  594.     if (!devport)
  595.         return (FALSE);
  596.     for (i = 1; i < 7; i++)
  597.         args[i] = 0;
  598.     /*
  599.      *        Some horrible messing around to make a BSTR
  600.      */
  601.     diskname = AllocMem(strlen(volname)+1,MEMF_PUBLIC);
  602.     strcpy(diskname+1, volname);
  603.     *diskname = strlen(volname);
  604.     args[0] = ((long)diskname)>>2;
  605.     if (!SendPacket(ACTION_RENAME_DISK, args, devport, NULL))
  606.         print("(Couldn't relabel disk\n");
  607.     /* Don't return an error, even if SendPacket failed! */
  608.     FreeMem(diskname, strlen(volname)+1);
  609.     return (TRUE);
  610. }
  611. #endif RAMBO
  612.  
  613.  
  614. /*
  615.  *        mainline()
  616.  *        ----------
  617.  */
  618. void main(argc,argv)
  619. int argc;
  620. char **argv;
  621. {
  622.     unsigned int start, end, newstart;            /* Cylinder numbers */
  623.  
  624. #ifdef RAMBO
  625. /************************* Start of RAMBO Stuff ***************************/
  626.  
  627.     int doload  = FALSE; /* If true, always copy to device even if mounted */
  628.  
  629.     if (argc > 1 && argv[1][0] == '-') { /* Handle Rambo options */
  630.         static char tempname[200];
  631.         while (argc > 1 && argv[1][0] == '-') {
  632.             char *str = &argv[1][2];        /* Have handy ptr to string    */
  633.             int num = atoi(str);            /* Have parameter ready        */
  634.  
  635.             switch (argv[1][1]) {
  636.  
  637.                 case 'v':                /* Set volume name */
  638.                     volname = str;
  639.                     break;
  640.  
  641.                 case 'n':                /* Set device name */
  642.                     /* Strip trailing ':' */
  643.                     if (LASTCHAR(str) == ':')
  644.                         LASTCHAR(str) = '\0';
  645.                     mount.dosname = str;
  646.                     break;
  647.  
  648.                 case 'd':                /* Set exec device name */
  649.                     mount.execname = str;
  650.                     break;
  651.  
  652.                 case 'u':                /* Set device unit number */
  653.                     mount.unit = num;
  654.                     break;
  655.  
  656.                 case 'f':                /* Set flags for OpenDevice() */
  657.                     mount.flags = num;
  658.                     break;
  659.  
  660.                 case 't':                /* Set number of tracks/cylinders */
  661.                     mount.highcyl = num - 1;
  662.                     break;
  663.  
  664.                 case 'm':                /* Set memory type */
  665.                     mount.bufmemtype = num;
  666.                     break;
  667.  
  668.                 case 'p':                /* Set boot priority */
  669.                     bootpri = num;
  670.                     break;
  671.  
  672.                 case 'e':                /* Echo message to stdout */
  673.                     print2(&argv[1][2], "\n");
  674.                     break;
  675.  
  676.                 case 'a':                /* Force loading into RAD: */
  677.                     doload  = TRUE;
  678.                     break;
  679.  
  680.                 default:
  681.                     print3("Unknown switch ", argv[1], "\n");
  682.                     help();
  683.                     cleanup(5);
  684.             }
  685.             argv++;
  686.             argc--;
  687.         }
  688.  
  689.         /*
  690.          *        Setup defaults for mount okay. Now see if the device is
  691.          *        to be mounted. If it is, then try and mount it. If it was
  692.          *        already mounted, then quit immediately, unless forceload is
  693.          *        in effect.
  694.          *
  695.          *        Else, see are there any files in RAD:. If there are, quit
  696.          *        immediately (since we are under Kikstart 1.2, and RAD: has
  697.          *        just recovered itself from memory), unless forceload is
  698.          *        in effect.
  699.          */
  700.         strcpy(tempname, mount.dosname);
  701.         strcat(tempname, ":");
  702.         if (!GetVolume(tempname, NULL)) {
  703.  
  704.             if (!mountramdisk()) {
  705.                 print3("Error: Couldn't mount device ",tempname,"\n");
  706.                 cleanup(20);
  707.             }
  708.         }
  709.         /*
  710.          *        Scan device and see if there are files on it.
  711.          *        Do this by seeing if there are any files in
  712.          *        the directory. If there aren't, then we can
  713.          *        force the load, otherwise don't force it.
  714.          */
  715.         {
  716.             struct FileInfoBlock *fib;
  717.             BPTR lock;
  718.  
  719.             fib = AllocMem(sizeof(struct FileInfoBlock), 0L);
  720.             if (!fib) {
  721.                 print("Out of memory allocating FileInfoBlock!\n");
  722.                 cleanup(20);
  723.             }
  724.             lock = Lock(tempname, ACCESS_READ);
  725.             if (lock) {
  726.                 if (Examine(lock, fib)) {
  727.                     if (!ExNext(lock, fib))
  728.                         doload = TRUE;
  729.                 }
  730.                 UnLock(lock);
  731.             }
  732.             FreeMem(fib, sizeof(struct FileInfoBlock));
  733.         }
  734.  
  735.         /*
  736.          *        Now see if after all that, we still want to go
  737.          *        ahead with the load into RAD:. If not, then just
  738.          *        exit silently (to let the startup-sequence carry
  739.          *        on okay).
  740.          */
  741.         if (!doload)
  742.             cleanup(0);
  743.     }
  744.  
  745. /************************* End of RAMBO Stuff ***************************/
  746. #endif RAMBO
  747.  
  748. #define NONUM(x) (!isdigit(argv[x][0]))
  749.  
  750.     if (argc != 6 || NONUM(3) || NONUM(4) || NONUM(5)) {
  751.         help();
  752.         cleanup(5);
  753.     }
  754.  
  755.     srcname  = argv[1];
  756.     destname = argv[2];
  757.     start    = atoi(argv[3]);
  758.     end      = atoi(argv[4]);
  759.     newstart = atoi(argv[5]);
  760.  
  761.     if (!GetVolume(srcname, src)) {
  762.         print2(srcname, " is not a valid disk device\n");
  763.         cleanup(20);
  764.     }
  765.  
  766.     if (!GetVolume(destname, dest)) {
  767.         print2(destname, " is not a valid disk device\n");
  768.         cleanup(20);
  769.     }
  770.  
  771. #define NOTSAME(x) (src->x != dest->x)
  772.  
  773.     if (NOTSAME(blocksize) || NOTSAME(blockspertrack) || NOTSAME(surfaces)) {
  774.         print3(srcname, " and ", destname);
  775.         print(" do not have same track sizes\n");
  776.         cleanup(20);
  777.     }
  778.  
  779.     if (start > end) {
  780.         print("Start track is greater than end track.\n");
  781.         cleanup(20);
  782.     }
  783.  
  784.     if (end >= src->numcyl) {
  785.         print3("Maximum end track on ", srcname, " is");
  786.         print2(numtostr(src->numcyl - 1), ".\n");
  787.         cleanup(20);
  788.     }
  789.  
  790.     if ((newstart + (end - start)) >= dest->numcyl) {
  791.         print2("There is not room for ", numtostr(1 + end - start));
  792.         print3(" tracks on ", destname, "\n");
  793.         cleanup(20);
  794.     }
  795.  
  796.     destport = (MSGPORT *)DeviceProc(destname);
  797.     if (!destport) {
  798.         print3("Can't locate process for device ", destname,"\n");
  799.         cleanup(20);
  800.     }
  801.  
  802.     /*
  803.      *        The two devices are valid, so now open the exec devices which
  804.      *        they use.
  805.      */
  806.     opendevs();
  807.     inhibit(destport, TRUE);
  808.     inhibited = TRUE;
  809.     copytracks(start, end, newstart);
  810.     cleanup(0);
  811. }
  812.